#include <iostream>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <vector>
#include <cstdlib>
#include <cassert>
#include <unordered_map>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>

using namespace std;

typedef void (*functor)(); // 函数指针
vector<functor> functors;  // 方法集合
// for debug
unordered_map<uint32_t, string> info;

void f1()
{
    cout << "这是一个处理日志的任务，执行的进程 ID [" << getpid() << "]"
         << "执行时间是[" << time(nullptr) << "]\n" << endl;
}

void f2()
{
    cout << "这是一个备份任务，执行的进程 ID [" << getpid() << "]"
         << "执行时间是[" << time(nullptr) << "]\n" << endl;
}
void f3()
{
    cout << "这是一个处理网络连接的任务，执行的进程 ID [" << getpid() << "]"
         << "执行时间是[" << time(nullptr) << "]\n" << endl;
}

void loadFunctor()
{
    info.insert({functors.size(), "处理日志的任务"});
    functors.push_back(f1);

    info.insert({functors.size(), "备份数据任务"});
    functors.push_back(f2);

    info.insert({functors.size(), "处理网络连接的任务"});
    functors.push_back(f3);
}

typedef pair<int32_t,int32_t> elem;
//第一个int32_t:进程pid，第二个int32_t:该进程对应的管道写端fd
vector<elem> assignMap;
int processNum = 5;

void work(int blockFd)
{
    cout << "进程[" << getpid() << "]" << "开始工作" << endl;
    // 子进程核心工作的代码
    while (true)
    {
        // a.阻塞等待  b.获取任务
        uint32_t operatorCode = 0;
        ssize_t s = read(blockFd, &operatorCode, sizeof(uint32_t));
        if (s == 0)
            break;
        assert(s == sizeof(uint32_t));
        (void)s;

        // c.处理任务
        if (operatorCode < functors.size())
            functors[operatorCode]();
    }
    cout<<"进程["<<getpid()<<"]"<<"结束工作"<<endl;
}
//[子进程的pid,子进程的管道fd]
void balancesendTask(const vector<elem> &processFds)
{
    srand((long long)time(nullptr));
    while(true)
    {
        sleep(1);
        //选择一个进程,选择进程是随机的，没有压着一个进程给任务
        //较为均匀的将任务给所有的子进程——负载均衡
        uint32_t pick = rand()% processFds.size();

        //选择一个任务
        uint32_t task = rand()%functors.size();

        //把任务给一个指定的进程
        write(processFds[pick].second,&task,sizeof(task));

        //打印对应的提示信息
        cout << "父进程指派任务——>" << info[task] << "给进程："
             << processFds[pick].first << "编号：" << pick << endl;
    }
}
int main()
{
    loadFunctor();
    vector<elem> assignMap;
    // 创建processNum个进程
    for(int  i =0; i< processNum;i++)
    {
        //定义保存管道上fd的对象
        int pipefd[2] = {0};
        //创建管道
        pipe(pipefd);
        //创建子进程
        pid_t id = fork();
        if( id == 0)
        {
            //子进程读取
            close(pipefd[1]);
            //子进程执行
            work(pipefd[0]);
            close(pipefd[0]);
            exit(0);
        }
        // 父进程做的事情
        close(pipefd[0]);
        elem e(id, pipefd[1]);
        assignMap.push_back(e);
    }
    cout<<"Create All Process Success!"<<endl;
    //父进程，派发任务
    balancesendTask(assignMap);
    //回收资源
    for (int i = 0; i < processNum; i++)
    {
        if (waitpid(assignMap[i].first, nullptr, 0) > 0)
        {
            cout << "Wait for: pid=" << assignMap[i].first << "Wait Success!"
                 << "number:" << i << endl;
        }
    }
}


//2.父进程控制子进程
// typedef void (*functor)(); // 函数指针
// vector<functor> functors;  // 方法集合
// // for debug
// unordered_map<uint32_t, string> info;

// void f1()
// {
//     cout << "这是一个处理日志的任务，执行的进程 ID [" << getpid() << "]"
//          << "执行时间是[" << time(nullptr) << "]" << endl;
// }

// void f2()
// {
//     cout << "这是一个备份任务，执行的进程 ID [" << getpid() << "]"
//          << "执行时间是[" << time(nullptr) << "]" << endl;
// }
// void f3()
// {
//     cout << "这是一个处理网络连接的任务，执行的进程 ID [" << getpid() << "]"
//          << "执行时间是[" << time(nullptr) << "]" << endl;
// }

// void loadFunctor()
// {
//     info.insert({functors.size(), "处理日志的任务"});
//     functors.push_back(f1);

//     info.insert({functors.size(), "备份数据任务"});
//     functors.push_back(f2);

//     info.insert({functors.size(), "处理网络连接的任务"});
//     functors.push_back(f3);
// }
// int main()
// {
//     // 0.加载任务列表
//     loadFunctor();

//     // 1.创建管道
//     int pipefd[2] = {0};
//     if (pipe(pipefd) != 0)
//     {
//         cerr << "pipe error" << endl;
//         return 1;
//     }

//     // 2.创建子进程
//     pid_t id = fork();
//     if (id < 0)
//     {
//         cerr << "fork error" << endl;
//         return 2;
//     }
//     else if (id == 0)
//     {
//         // 3.关闭不需要的文件fd
//         //  child,read
//         close(pipefd[1]);
//         // 4.业务处理
//         while (true)
//         {
//             uint32_t operatorType = 0;
//             // 如果有数据就读取。如果没有数据，就阻塞等待，等待任务的到来
//             ssize_t s = read(pipefd[0], &operatorType, sizeof(uint32_t));
//             if(s == 0)
//             {
//                 cout<<"需求已完成，我即将退出服务状态!"<<endl;
//                 break;
//             }
//             assert(s == sizeof(uint32_t));
//             (void)s;
//             // assert断言，是编译有效debug模式。release模式，断言就没有了。
//             // 一旦断言没有了，s变量就是只被定义了，没有被使用。release模式中，可能会有warning

            
//             if (operatorType < functors.size())
//             {
//                 functors[operatorType]();
//             }
//             else
//             {
//                 cerr << "bug? operatorType = " << operatorType << endl;
//             }
//         }
//         close(pipefd[0]);
//         exit(0);
//     }
//     else
//     {
//         srand((long long)time(nullptr));
//         // parent,write-操作
//         // 关闭不需要的文件fd
//         close(pipefd[0]);
//         // 指派任务
//         int num = functors.size();
//         int cnt = 10; // 设定10个任务
//         while (cnt--)
//         {
//             // 形成任务码
//             uint32_t commandCode = rand() % num;
//             cout << "父进程指派任务完成，任务是：" << info[commandCode] << "任务的编号是：" << cnt << endl;
//             // 向指定的进程下达执行任务的操作
//             write(pipefd[1], &commandCode, sizeof(uint32_t));
//             sleep(1);
//         }
//         close(pipefd[1]);
//         pid_t res = waitpid(id, nullptr, 0);
//         if (res)
//         {
//             cout << "Wait Success！" << endl;
//         }
//     }
//     return 0;
// }

// 1.演示管道通信基本过程(这里是匿名管道)
//  int main()
//  {
//      //1.创建管道
//      int pipefd[2] = {0};
//      if (pipe(pipefd) != 0)
//      {
//          cerr << "pipe" << endl;
//          return 1;
//      }

//     // 2.创建子进程
//     pid_t id = fork();
//     if (id < 0)
//     {
//         cerr << "fork error" << endl;
//         return 2;
//     }
//     else if( id == 0)
//     {
//         //child
//         //子进程来进行读取，子进程就应该关掉写端
//         close(pipefd[1]);
//         #define NUM 1024
//         char buffer[NUM];
//         while(true)
//         {
//             //子进程没有调用sleep函数，为什么也会休眠呢？
//             cout<< "时间戳："<<(uint64_t)time(nullptr)<<endl;
//             memset(buffer,0,sizeof(buffer));
//             ssize_t s = read(pipefd[0],buffer,sizeof(buffer)-1);
//             if(s>0)
//             {
//                 //读取成功
//                 buffer[s] = '\0';
//                 cout<< "子进程收到消息，内容是："<<buffer<<endl;
//             }
//             else if(s == 0)
//             {
//                 cout<< "父进程写完，子进程退出！"<<endl;
//                 break;
//             }
//             else
//             {
//                 //Do Nothing
//             }
//         }
//         close(pipefd[0]);
//         exit(0);

//     }
//     else
//     {
//         //parent
//         //父进程来进行写入，就应该关掉读端
//         //方式1
//         // close(pipefd[0]);
//         // string msg = "你好，子进程！我是父进程！";
//         // int cnt = 0;
//         // while(cnt < 5)
//         // {
//         //     write(pipefd[1],msg.c_str(),msg.size()); //这里无需对字符串+1，因为管道也是文件，无需对字符串的结尾\0区别
//         //     sleep(1);  //这里只是为了观察打印现象明显
//         //     cnt++;
//         // }

//         //方式2
//         close(pipefd[0]);
//         const char *msg = "你好子进程,我是父进程,这次发送的信息编号是";
//         int cnt = 0;
//         while(cnt < 5)
//         {
//             char sendBuffer[1024];
//             sprintf(sendBuffer,"%s : %d",msg,cnt);
//             write(pipefd[1],sendBuffer,strlen(sendBuffer)); //这里无需对字符串+1，因为管道也是文件，无需对字符串的结尾\0区别
//             sleep(1);  //这里只是为了观察打印现象明显
//             cnt++;
//         }
//         close(pipefd[1]);
//         cout<<"父进程写完了！"<<endl;
//     }
//     //0——>嘴巴 ——>读
//     //1——>笔  ——>写
//    pid_t res = waitpid(id,nullptr,0);
//    if(res > 0)
//    {
//     cout<<"等待子进程成功！"<<endl;
//    }
//     return 0;
// }

// int main()
// {
//     int pipefd[2] = {0};
//     if (pipe(pipefd) != 0)
//     {
//         cerr << "pipe" << endl;
//         return 1;
//     }

//     cout << "fd[0]: "<<pipefd[0]<<endl;
//     cout << "fd[1]: "<<pipefd[1]<<endl;
//     return 0;
// }
